
#include "video.h"
#include "debug.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <fcntl.h>
#include <unistd.h>

#include <sys/ioctl.h>
#include <sys/mman.h>

#include <linux/fb.h>
#include <linux/videodev2.h>

#define N_BUF				1
#define VIDEO_NO			0

#define DEV_VIDEO_NAME			(char *)"/dev/video0"
#define DEV_FB_NAME			(char *)"/dev/fb0"

static unsigned int *fb_addr = NULL;

static int device_init(struct camera_class *cam)
{
	if(0 != cam->video_open(cam))
	{
		ERR_DUMP("video_open()");
		return -1;
	}

	cam->show_cap(cam);

	//cam->enum_fmt(cam);

	if(0 != cam->set_fmt(cam))
	{
#if !IGNORE_S_FMT
		ERR_DUMP("set_fmt()");
		return -1;
#else
		WAR_DUMP("set_fmt()");
#endif
	}

#if IGNORE_S_FMT
	errno = 0;
#endif

	if(N_BUF != cam->req_buf(cam, N_BUF))
	{
		ERR_DUMP("req_buf()");
		return -1;
	}

	if(0 != cam->alloc_buf(cam))
	{
		ERR_DUMP("alloc_buf()");
		return -1;
	}

	if(0 != cam->mmap_buf(cam))
	{
		ERR_DUMP("mmap_buf()");
		return -1;
	}

	if(0 != cam->init_buf(cam))
	{
		ERR_DUMP("push_buf()");
		return -1;
	}
	return 0;
}

int main(int argc, char **argv)
{
	int fd = -1;

	struct camera_buf *buf_tmp = NULL;
	struct camera_class *cam = NULL;

	struct fb_var_screeninfo vinfo;
	size_t fb_size = 0;

	fd = open(DEV_FB_NAME, O_RDWR);

	if (fd < 0) {
		perror(DEV_FB_NAME);
		return -1;
	}

	if(0 != ioctl(fd, FBIOGET_VSCREENINFO, &vinfo))
	{
		perror(DEV_FB_NAME);
		return -1;
	}

	fb_size = vinfo.xres * vinfo.yres * (vinfo.bits_per_pixel / 8);

	printf("widht = %d, heitht = %d, fb_bpp = %d, fb_size = %d\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel, fb_size);

	fb_addr = (unsigned int *)mmap(0, fb_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

	if(MAP_FAILED == fb_addr)
	{
		perror(DEV_FB_NAME);
		return -1;
	}

	cam = video_init(DEV_VIDEO_NAME, VIDEO_NO, vinfo.xres, vinfo.yres, V4L2_PIX_FMT_RGB32);

	if(NULL == cam)
	{
		ERR_DUMP("video_init()");
		return -1;
	}
	
	if(0 != device_init(cam))
	{
		ERR_DUMP("device_init()");
		return -1;
	}

	if(0 != cam->start_stream(cam))
	{
		ERR_DUMP("start_stream()");
		return -1;
	}

	INF_DUMP("Camera start streaming");

	cam->ignore_frame(cam, 1, 50);

	INF_DUMP("Camera ignore frame finish");

	while(1)
	{
		if(0 != cam->get_frame(cam, 3))
		{
			//ERR_DUMP("get_frame()");
			sleep(1);
			continue;
		}

		//INF_DUMP("Camera get frame finish");

		if(0 != cam->pop_buf(cam))
		{
			//ERR_DUMP("pop_buf()");
			sleep(1);
			continue;
		}

		//INF_DUMP("Camera pop buffer finish");

		if(NULL == buf_tmp)
		{
			if(0 != cam->get_bufdup(cam, &buf_tmp))
			{
				//ERR_DUMP("get_bufdup()");
			}
		}
		
		if(NULL == buf_tmp)
		{
			//WAR_DUMP("get_bufdup");
		}

		//INF_DUMP("Camera dup buffer finish");

		if(0 != cam->push_buf(cam))
		{
			//ERR_DUMP("push_buf()");
			sleep(1);
			continue;
		}

		//INF_DUMP("Camera push buffer finish");
		
		if(fb_size == buf_tmp->length)
		{
			memcpy(fb_addr, buf_tmp->start, buf_tmp->length);
			INF_DUMP("write success");
		}
		
		cam->free_bufdup(cam, &buf_tmp);
	}

	printf("Done, press any key to continue\n");
	getchar();
	munmap(fb_addr, fb_size);
	close(fd);
	return 0;
}
